{
OstreeMetalink *metalink;
- GTask *task;
+ GCancellable *cancellable;
GMarkupParseContext *parser;
guint passthrough_depth;
gpointer user_data,
GError **error)
{
- GTask *task = user_data;
- OstreeMetalinkRequest *self = g_task_get_task_data (task);
+ OstreeMetalinkRequest *self = user_data;
switch (self->state)
{
gpointer user_data,
GError **error)
{
- GTask *task = user_data;
- OstreeMetalinkRequest *self = g_task_get_task_data (task);
+ OstreeMetalinkRequest *self = user_data;
switch (self->state)
{
gpointer user_data,
GError **error)
{
- GTask *task = user_data;
- OstreeMetalinkRequest *self = g_task_get_task_data (task);
+ OstreeMetalinkRequest *self = user_data;
switch (self->state)
{
return self;
}
-static void
-try_next_url (OstreeMetalinkRequest *self);
-
static gboolean
valid_hex_checksum (const char *s, gsize expected_len)
{
return len == expected_len && s[len] == '\0';
}
-static void
-on_fetched_url (GObject *src,
- GAsyncResult *res,
- gpointer user_data)
+static gboolean
+try_one_url (OstreeMetalinkRequest *self,
+ SoupURI *uri,
+ GBytes **out_data,
+ GError **error)
{
- GTask *task = user_data;
- GCancellable *cancellable;
- OstreeMetalinkRequest *self = g_task_get_task_data (task);
- GError *local_error = NULL;
- int parent_dfd = _ostree_fetcher_get_dfd (self->metalink->fetcher);
- g_autoptr(GInputStream) instream = NULL;
- g_autoptr(GOutputStream) outstream = NULL;
+ gboolean ret = FALSE;
g_autoptr(GBytes) bytes = NULL;
- g_autofree char *path = NULL;
gssize n_bytes;
- path = _ostree_fetcher_request_uri_with_partial_finish ((OstreeFetcher*)src, res, &local_error);
- if (!path)
+ if (!_ostree_fetcher_request_uri_to_membuf (self->metalink->fetcher,
+ uri,
+ FALSE,
+ FALSE,
+ &bytes,
+ self->metalink->max_size,
+ self->cancellable,
+ error))
goto out;
- cancellable = g_task_get_cancellable (task);
-
- if (!ot_openat_read_stream (parent_dfd, path, FALSE, &instream,
- cancellable, &local_error))
- goto out;
-
- outstream = g_memory_output_stream_new_resizable ();
-
- n_bytes = g_output_stream_splice (outstream, instream,
- G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
- G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
- cancellable, &local_error);
-
- if (n_bytes < 0)
- goto out;
-
- bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (outstream));
-
+ n_bytes = g_bytes_get_size (bytes);
if (n_bytes != self->size)
{
- g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Expected size is %" G_GUINT64_FORMAT " bytes but content is %" G_GSSIZE_FORMAT " bytes",
self->size, n_bytes);
goto out;
if (strcmp (self->verification_sha512, actual) != 0)
{
- g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Expected checksum is %s but actual is %s",
self->verification_sha512, actual);
goto out;
if (strcmp (self->verification_sha256, actual) != 0)
{
- g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Expected checksum is %s but actual is %s",
self->verification_sha256, actual);
goto out;
}
}
+ ret = TRUE;
+ if (out_data)
+ *out_data = g_bytes_ref (bytes);
out:
- if (local_error)
- {
- g_free (self->last_metalink_error);
- self->last_metalink_error = g_strdup (local_error->message);
- g_clear_error (&local_error);
-
- /* And here we iterate on the next one if we hit an error */
- self->current_url_index++;
- try_next_url (self);
- }
- else
- {
- self->result = g_bytes_ref (bytes);
- g_task_return_boolean (self->task, TRUE);
- }
-}
-
-static void
-try_next_url (OstreeMetalinkRequest *self)
-{
- if (self->current_url_index >= self->urls->len)
- {
- g_task_return_new_error (self->task, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Exhausted %u metalink targets, last error: %s",
- self->urls->len, self->last_metalink_error);
- }
- else
- {
- SoupURI *next = self->urls->pdata[self->current_url_index];
-
- _ostree_fetcher_request_uri_with_partial_async (self->metalink->fetcher, next,
- self->metalink->max_size,
- OSTREE_FETCHER_DEFAULT_PRIORITY,
- g_task_get_cancellable (self->task),
- on_fetched_url, self->task);
- }
+ return ret;
}
static gboolean
-start_target_request_phase (OstreeMetalinkRequest *self,
- GError **error)
+try_metalink_targets (OstreeMetalinkRequest *self,
+ SoupURI **out_target_uri,
+ GBytes **out_data,
+ GError **error)
{
gboolean ret = FALSE;
+ SoupURI *target_uri;
if (!self->found_a_file_element)
{
goto out;
}
- try_next_url (self);
+ for (self->current_url_index = 0;
+ self->current_url_index < self->urls->len;
+ self->current_url_index++)
+ {
+ GError *temp_error = NULL;
+
+ target_uri = self->urls->pdata[self->current_url_index];
+
+ if (try_one_url (self, target_uri, out_data, &temp_error))
+ break;
+ else
+ {
+ g_free (self->last_metalink_error);
+ self->last_metalink_error = g_strdup (temp_error->message);
+ g_clear_error (&temp_error);
+ }
+ }
+
+ if (self->current_url_index >= self->urls->len)
+ {
+ g_assert (self->last_metalink_error != NULL);
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Exhausted %u metalink targets, last error: %s",
+ self->urls->len, self->last_metalink_error);
+ goto out;
+ }
ret = TRUE;
+ if (out_target_uri)
+ *out_target_uri = soup_uri_copy (target_uri);
out:
return ret;
}
-static void
-ostree_metalink_request_unref (gpointer data)
-{
- OstreeMetalinkRequest *request = data;
- g_object_unref (request->metalink);
- g_clear_pointer (&request->result, g_bytes_unref);
- g_free (request->last_metalink_error);
- g_ptr_array_unref (request->urls);
- g_free (request);
-}
-
static const GMarkupParser metalink_parser = {
metalink_parser_start,
metalink_parser_end,
GMainLoop *loop;
} FetchMetalinkSyncData;
-static gboolean
-ostree_metalink_request_finish (OstreeMetalink *self,
- GAsyncResult *result,
- SoupURI **out_target_uri,
- GBytes **out_data,
- GError **error)
-{
- OstreeMetalinkRequest *request;
-
- g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
-
- request = g_task_get_task_data ((GTask*)result);
-
- if (g_task_propagate_boolean ((GTask*)result, error))
- {
- g_assert_cmpint (request->current_url_index, <, request->urls->len);
- if (out_target_uri != NULL)
- *out_target_uri = request->urls->pdata[request->current_url_index];
- if (out_data != NULL)
- *out_data = g_bytes_ref (request->result);
- return TRUE;
- }
- else
- return FALSE;
-}
-
-static void
-on_metalink_fetched (GObject *src,
- GAsyncResult *result,
- gpointer user_data)
-{
- FetchMetalinkSyncData *data = user_data;
-
- data->success = ostree_metalink_request_finish ((OstreeMetalink*)src,
- result,
- data->out_target_uri,
- data->out_data,
- data->error);
- g_main_loop_quit (data->loop);
-}
-
-static gboolean
-on_metalink_bytes_read (OstreeMetalinkRequest *self,
- OstreeMetalinkRequest *request,
- FetchMetalinkSyncData *sync_data,
- GBytes *bytes,
- GError **error)
-{
- gsize len;
- const guint8 *data = g_bytes_get_data (bytes, &len);
- if (!g_markup_parse_context_parse (self->parser, (const char*)data, len, error))
- return FALSE;
-
- if (!start_target_request_phase (self, error))
- return FALSE;
-
- return TRUE;
-}
-
gboolean
_ostree_metalink_request_sync (OstreeMetalink *self,
- GMainLoop *loop,
SoupURI **out_target_uri,
GBytes **out_data,
SoupURI **fetching_sync_uri,
GCancellable *cancellable,
GError **error)
{
- OstreeMetalinkRequest *request = g_new0 (OstreeMetalinkRequest, 1);
- FetchMetalinkSyncData data = { 0, };
- GTask *task = g_task_new (self, cancellable, on_metalink_fetched, &data);
- GBytes *out_contents = NULL;
gboolean ret = FALSE;
-
- data.out_target_uri = out_target_uri;
- data.out_data = out_data;
- data.loop = loop;
- data.error = error;
+ OstreeMetalinkRequest request = { 0, };
+ g_autoptr(GMainContext) mainctx = NULL;
+ GBytes *out_contents = NULL;
+ gsize len;
+ const guint8 *data;
if (fetching_sync_uri != NULL)
*fetching_sync_uri = _ostree_metalink_get_uri (self);
- request->metalink = g_object_ref (self);
- request->urls = g_ptr_array_new_with_free_func ((GDestroyNotify) soup_uri_free);
- request->task = task; /* Unowned */
-
- request->parser = g_markup_parse_context_new (&metalink_parser, G_MARKUP_PREFIX_ERROR_POSITION, task, NULL);
-
- g_task_set_task_data (task, request, ostree_metalink_request_unref);
-
- if (! _ostree_fetcher_request_uri_to_membuf (self->fetcher,
- self->uri,
- FALSE,
- FALSE,
- &out_contents,
- loop,
- self->max_size,
- cancellable,
- error))
+ mainctx = g_main_context_new ();
+ g_main_context_push_thread_default (mainctx);
+
+ request.metalink = g_object_ref (self);
+ request.urls = g_ptr_array_new_with_free_func ((GDestroyNotify) soup_uri_free);
+ request.parser = g_markup_parse_context_new (&metalink_parser, G_MARKUP_PREFIX_ERROR_POSITION, &request, NULL);
+
+ if (!_ostree_fetcher_request_uri_to_membuf (self->fetcher,
+ self->uri,
+ FALSE,
+ FALSE,
+ &out_contents,
+ self->max_size,
+ cancellable,
+ error))
goto out;
- if (! on_metalink_bytes_read (request, request, &data, out_contents, error))
+ data = g_bytes_get_data (out_contents, &len);
+ if (!g_markup_parse_context_parse (request.parser, (const char*)data, len, error))
goto out;
- g_main_loop_run (data.loop);
-
- ret = data.success;
+ if (!try_metalink_targets (&request, out_target_uri, out_data, error))
+ goto out;
+ ret = TRUE;
out:
+ if (mainctx)
+ g_main_context_pop_thread_default (mainctx);
+ g_clear_object (&request.metalink);
+ g_clear_pointer (&request.urls, g_ptr_array_unref);
+ g_clear_pointer (&request.parser, g_markup_parse_context_free);
return ret;
}
OstreeRepo *remote_repo_local;
GMainContext *main_context;
- GMainLoop *loop;
GCancellable *cancellable;
OstreeAsyncProgress *progress;
return TRUE;
}
-static void
-throw_async_error (OtPullData *pull_data,
- GError *error)
-{
- if (error)
- {
- if (!pull_data->caught_error)
- {
- pull_data->caught_error = TRUE;
- g_propagate_error (pull_data->async_error, error);
- g_main_loop_quit (pull_data->loop);
- }
- else
- {
- g_error_free (error);
- }
- }
-}
-
-static void
-check_outstanding_requests_handle_error (OtPullData *pull_data,
- GError *error)
+/* The core logic function for whether we should continue the main loop */
+static gboolean
+pull_termination_condition (OtPullData *pull_data)
{
gboolean current_fetch_idle = (pull_data->n_outstanding_metadata_fetches == 0 &&
pull_data->n_outstanding_content_fetches == 0 &&
pull_data->n_outstanding_deltapart_write_requests == 0 );
gboolean current_idle = current_fetch_idle && current_write_idle;
- throw_async_error (pull_data, error);
+ if (pull_data->caught_error)
+ return TRUE;
switch (pull_data->phase)
{
case OSTREE_PULL_PHASE_FETCHING_REFS:
if (!pull_data->fetching_sync_uri)
- g_main_loop_quit (pull_data->loop);
+ return TRUE;
break;
case OSTREE_PULL_PHASE_FETCHING_OBJECTS:
if (current_idle && !pull_data->fetching_sync_uri)
{
g_debug ("pull: idle, exiting mainloop");
-
- g_main_loop_quit (pull_data->loop);
+ return TRUE;
}
break;
}
+ return FALSE;
}
-static gboolean
-idle_check_outstanding_requests (gpointer user_data)
+static void
+check_outstanding_requests_handle_error (OtPullData *pull_data,
+ GError *error)
{
- check_outstanding_requests_handle_error (user_data, NULL);
- return FALSE;
+ if (error)
+ {
+ if (!pull_data->caught_error)
+ {
+ pull_data->caught_error = TRUE;
+ g_propagate_error (pull_data->async_error, error);
+ }
+ else
+ {
+ g_error_free (error);
+ }
+ }
}
typedef struct {
add_nul,
allow_noent,
out_contents,
- pull_data->loop,
OSTREE_MAX_METADATA_SIZE,
cancellable,
error);
const char *dir_to_pull = NULL;
char **refs_to_fetch = NULL;
GSource *update_timeout = NULL;
- GSource *idle_src;
gboolean disable_static_deltas = FALSE;
if (options)
pull_data->async_error = error;
pull_data->main_context = g_main_context_ref_thread_default ();
- pull_data->loop = g_main_loop_new (pull_data->main_context, FALSE);
pull_data->flags = flags;
pull_data->repo = self;
soup_uri_free (metalink_uri);
if (! _ostree_metalink_request_sync (metalink,
- pull_data->loop,
&target_uri,
&summary_bytes,
&pull_data->fetching_sync_uri,
pull_data->phase = OSTREE_PULL_PHASE_FETCHING_OBJECTS;
+ /* Now discard the previous fetcher, as it was bound to a temporary main context
+ * for synchronous requests.
+ */
+ g_clear_object (&pull_data->fetcher);
+ pull_data->fetcher = _ostree_repo_remote_new_fetcher (self, remote_name_or_baseurl, error);
+ if (pull_data->fetcher == NULL)
+ goto out;
+
if (!ostree_repo_prepare_transaction (pull_data->repo, &pull_data->transaction_resuming,
cancellable, error))
goto out;
}
}
- idle_src = g_idle_source_new ();
- g_source_set_callback (idle_src, idle_check_outstanding_requests, pull_data, NULL);
- g_source_attach (idle_src, pull_data->main_context);
- g_source_unref (idle_src);
-
if (pull_data->progress)
{
update_timeout = g_timeout_source_new_seconds (1);
g_source_set_priority (update_timeout, G_PRIORITY_HIGH);
g_source_set_callback (update_timeout, update_progress, pull_data, NULL);
- g_source_attach (update_timeout, g_main_loop_get_context (pull_data->loop));
+ g_source_attach (update_timeout, pull_data->main_context);
g_source_unref (update_timeout);
}
/* Now await work completion */
- g_main_loop_run (pull_data->loop);
+ while (!pull_termination_condition (pull_data))
+ g_main_context_iteration (pull_data->main_context, TRUE);
if (pull_data->caught_error)
goto out;
g_main_context_unref (pull_data->main_context);
if (update_timeout)
g_source_destroy (update_timeout);
- if (pull_data->loop)
- g_main_loop_unref (pull_data->loop);
g_strfreev (configured_branches);
g_clear_object (&pull_data->fetcher);
g_clear_object (&pull_data->remote_repo_local);